import 'dart:async';
import 'dart:convert';
// import 'dart:html';

import 'package:encrypt/encrypt.dart';
import 'package:lib_bitcoin_base/bitcoin_base.dart';
import 'package:flutter/foundation.dart';
import 'config.dart';
import 'network.dart';
import 'package:wallet_sdk/wallet.dart';

class WalletUtils {
  WalletUtils._privateConstructor();

  static final WalletUtils _instance = WalletUtils._privateConstructor();

  factory WalletUtils() {
    return _instance;
  }

  String createMnemonic() {
    return generateMnemonic().join(" ");
  }

  String generateAddress(String pk, Chain chain) {
    if (chain == ChainList.btcChain || chain == ChainList.btcTestChain) {
      Map<BitcoinAddressType, String> res = SimpleBitcoin()
          .generateBitcoinAddress(pk, chain == ChainList.btcChain);
      return res[BitcoinAddressType.nativeSegWit]!;
    }
    Coin? coin = _getCoinByChain(chain);
    if (null == coin) {
      throw Exception("don't support");
    }

    return coin.createAddress(
        coin.createPublicKey(PrivateKey(BigInt.parse(pk, radix: 16))));
  }

  // 获取MPC 公钥地址
  String generateMPCAddress(String pk, Chain chain) {
    // 获取 比特币 公钥地址 mpc 暂时 不支持
    // if (chain == ChainList.btcChain || chain == ChainList.btcTestChain) {
    //   Map<BitcoinAddressType, String> res = SimpleBitcoin()
    //       .generateBitcoinAddress(pk, chain == ChainList.btcChain);
    //   return res[BitcoinAddressType.nativeSegWit]!;
    // }
    Coin? coin = const Sol();
    return coin.createAddress(PublicKey(decodeHexString(pk)));
  }

  String signData(String pk, String message, Chain chain) {
    Coin? coin = _getCoinByChain(chain);
    if (null == coin) {
      throw Exception("don't support");
    }

    List<int> messageUint8List = utf8.encode(message);

    return utf8.decode(coin.generateSignature(
        PrivateKey(BigInt.parse(pk, radix: 16)),
        Uint8List.fromList(messageUint8List)));
  }

  Coin? _getCoinByChain(Chain chain) {
    Coin? coin;
    if (chain.isBtcOrBtcTestnet()) {
      coin = const Bitcoin();
    } else if (chain.type == ChainType.eth) {
      coin = const Ethereum();
    } else if (chain.type == ChainType.tron) {
      coin = const Tron();
    } else if (chain.type == ChainType.sol) {
      coin = const Sol();
    }
    return coin;
  }

  Future<String> generatePkByMnemonic(String mnemonic, Chain chain) {
    return compute(_generatePkByMnemonic,
        {'mnemonic': mnemonic.split(' '), 'chain': chain});
  }

  String _generatePkByMnemonic(data) {
    // var seed = bip39.mnemonicToSeed(data['mnemonic']);
    // bip32.BIP32 node = bip32.BIP32.fromSeed(seed);
    // return HEX.encode(node.derivePath("m/44'/60'/0'/0/0").privateKey!);
    // return HEX.encode(node.derivePath("m/44'/195'/0'/0/0").privateKey!);
    // var path = (data['chain'] as Chain).derivePath;
    // return HEX.encode(node.derivePath(path).privateKey!);

    Chain chain = data['chain'];
    List<String> mnemonic = data['mnemonic'];
    Uint8List seed = mnemonicToSeed(mnemonic);
    Coin? coin;
    if (chain.isBtcOrBtcTestnet()) {
      // coin = const Bitcoin();
      return SimpleBitcoin()
          .generateBitcoinPrivateKeyHexByMnemonic(mnemonic.join(' '));
    } else if (chain.type == ChainType.eth) {
      coin = const Ethereum();
    } else if (chain.type == ChainType.tron) {
      coin = const Tron();
    }

    if (null == coin) {
      throw Exception("don't support");
    }

    final root = ExtendedPrivateKey.master(seed, xprv);

    final r = root.forPath(chain.derivePath);

    final sk = PrivateKey((r as ExtendedPrivateKey).key);

    // String pk = coin.createPrivateKey(seed).value.toRadixString(16);
    String pk = sk.value.toRadixString(16);
    Config.logger.d('mnemonic:$mnemonic,pk:$pk');
    while (pk.length < 64) {
      pk = '0$pk';
    }
    return pk;
  }
}
